﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SaveManager : MonoBehaviour
{
    private static SaveManager instance;
    public static SaveManager MyInstance
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<SaveManager>();
            }
            return instance;
        }
    }
    [SerializeField]
    private GameObject dialogWindowPopup;
    [SerializeField]
    private Text questionDialogWindow;
    [SerializeField]
    private Item[] items;
    int saveNumber = 0;
    private Chest[] chests;
    private charButton[] equipment;
    [SerializeField]
    private actionButton[] actionButtons;
    [SerializeField]
    private SavedCharacter[] saves;
    private string buttonEvent;
    private SavedCharacter curSavedGame;

    public Chest[] MyChests { get => chests; set => chests = value; }

    
    void Awake()
    {
        MyChests = FindObjectsOfType<Chest>();
        equipment = FindObjectsOfType<charButton>();
        foreach (SavedCharacter s in saves)
        {
            s.HideInfo();
            ShowSavedFiles(s);
        }

    }

    private void Start()
    {
        if (PlayerPrefs.HasKey("Load"))
        {
            Load(saves[PlayerPrefs.GetInt("Load")]);
            PlayerPrefs.DeleteKey("Load");
        }
        else
        {
            Player.MyInstance.SetDefaultValues();
        }
    }
    
    private void ShowSavedFiles(SavedCharacter sc)
    {
        if (File.Exists(Application.dataPath + "/publish/sav/" + sc.gameObject.name+".dat"))
        {
            
            BinaryFormatter bf = new BinaryFormatter();
            string filePath = Application.dataPath + "/publish/sav/" + sc.gameObject.name + ".dat";
            
            FileStream file = File.Open(Application.dataPath + "/publish/sav/" + sc.gameObject.name + ".dat",
                                        FileMode.Open);
            var info = new FileInfo(filePath);
           
            if (File.Exists(filePath)&&info.Length>0)
            {
                
                SaveScript data = (SaveScript)bf.Deserialize(file);//bug is somewhere around here
                //file.Close();
                sc.DisplayInfo(data);
                
            }
            file.Close();
            
            
        }
    }
    private void Save(SavedCharacter sc)
    {
        try
        {
            saveNumber++;
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(Application.dataPath + "/publish/sav/" + sc.gameObject.name + ".dat",
                                        FileMode.Create);
            
            SaveScript data = new SaveScript();
            data.MyScene = SceneManager.GetActiveScene().name;
            SaveEquipment(data);
            SavePlayer(data);
            SaveChest(data);
            SaveBag(data);
            SaveInventory(data);
            SaveActionButons(data);
            bf.Serialize(file, data);
            file.Close();
            ShowSavedFiles(sc);
            
        }
        catch(System.Exception)
        {
           
        }
    }
    private void SavePlayer(SaveScript data)
    {
        data.MyPlayerData = new PlayerData(
            Player.MyInstance.MyLevel,
            Player.MyInstance.MyExp.myVal,
            Player.MyInstance.MyExp.maxVal,
            Player.MyInstance.Health.myVal,
            Player.MyInstance.Health.maxVal,
            Player.MyInstance.transform.position,
            Player.MyInstance.MyName,
            Player.MyInstance.Stamina.myVal,
            Player.MyInstance.Stamina.maxVal,
            Player.MyInstance.Mana.myVal,
            Player.MyInstance.Mana.maxVal
            );
    }
    private void SaveChest(SaveScript data)
    {
        
        for(int i=0; i<MyChests.Length; i++)
        {
            
            data.MyChests.Add(new ChestData(MyChests[i].name));
            foreach (Item item in MyChests[i].MyItems)
            {
                
                if (MyChests[i].MyItems.Count > 0)
                {
                  
                    data.MyChests[i].MyItems.Add(new ItemData(item.MyTitle, item.Slot.MyItems.Count, item.Slot.MySlotIndex));
                  
                }
                
            }
        }
    }

    private void SaveBag(SaveScript data)
    {
        foreach(bag tempBag in inventoryScript.MyInstance.MyBags)
        {
            data.MyInventoryData.MyBags.Add(new BagData(tempBag.Slots, tempBag.MyBagButton.MyBagId));
            
        }
    }

    private void SaveInventory(SaveScript data)
    {

        List<slotScript> slots = inventoryScript.MyInstance.GetFullSlots();
        
        foreach(slotScript tempSlot in slots)
        {
            data.MyInventoryData.MyItems.Add(new ItemData(
                tempSlot.MyItem.MyTitle, 
                tempSlot.MyCount, 
                tempSlot.MySlotIndex, 
                tempSlot.MyBag.MyBagIndex));
        }
    }

    private void SaveEquipment(SaveScript data)
    {
        foreach(charButton tcb in equipment)
        {
            if (tcb.MyEquippedEquipment != null)
            {
                data.MyEquipment.Add(new EquipmentData(tcb.MyEquippedEquipment.MyTitle,tcb.name));
            }
        }
    }

    private void SaveActionButons(SaveScript data)
    {
       
        for(int i = 0; i < actionButtons.Length; i++)
        {
            if (actionButtons[i].MyUsable!=null)
            {
                ActionBarData tempABD;
                if(actionButtons[i].MyUsable is Spell)
                {
                    tempABD = new ActionBarData((actionButtons[i].MyUsable as Spell).MyTitle, i, false);
                }
                else
                {
                    tempABD=new ActionBarData((actionButtons[i].MyUsable as Item).MyTitle,i,true);
                }
                data.MyActionBar.Add(tempABD);
            }
            
        }
        
    }

    private void LoadPlayer(SaveScript data)
    {
        Player.MyInstance.MyLevel = data.MyPlayerData.MyLevel;
        Player.MyInstance.RefreshLvl();
        Player.MyInstance.MyExp.inicialize(data.MyPlayerData.MyExp, data.MyPlayerData.MyMaxExp); 
        Player.MyInstance.Health.inicialize(data.MyPlayerData.MyHP, data.MyPlayerData.MyMaxHP);
        Player.MyInstance.Stamina.inicialize(data.MyPlayerData.MySP, data.MyPlayerData.MyMaxSP);
        Player.MyInstance.Mana.inicialize(data.MyPlayerData.MyMP, data.MyPlayerData.MyMaxMP);
        Player.MyInstance.MyName = data.MyPlayerData.MyName;
        Player.MyInstance.transform.position = new Vector2(data.MyPlayerData.MyPosX, data.MyPlayerData.MyPosY);
    }
    private void LoadChest(SaveScript data)
    {
        foreach (ChestData chest in data.MyChests)
        {
            Chest chestTmp = Array.Find(MyChests, x => x.name == chest.MyChestTitle);

            foreach (ItemData itemData in chest.MyItems)
            {
                Item item = Instantiate(Array.Find(items, x => x.MyTitle == itemData.MyItemTitle));
                item.Slot = chestTmp.MyBag.MySlots.Find(x => x.MySlotIndex == itemData.MySlotIndex);
                chestTmp.MyItems.Add(item);
            }
        }
    }

    private void LoadBag(SaveScript data)
    { 
        foreach(BagData tempBagData in data.MyInventoryData.MyBags)
        {
            bag tempBag = (bag)Instantiate(items[0]);
            tempBag.initialize(tempBagData.MySlotCount);
            
            inventoryScript.MyInstance.addBag(tempBag, tempBagData.MyBagIndex);
        }
    }

    private void LoadInventory(SaveScript data)
    {
        foreach (ItemData itemData in data.MyInventoryData.MyItems)
        { 
            Item item = Instantiate(Array.Find(items, x => x.MyTitle == itemData.MyItemTitle));

            for (int i=0; i < itemData.MyStackCount; i++)
            {
                //inventoryScript.MyInstance.AddItem();
                //Item tempItem = (Item)Instantiate(item);
                inventoryScript.MyInstance.AddToSpecificSlot(item, itemData.MySlotIndex, itemData.MyBagIndex);
            }

            //Debug.Log("Loaded " + itemData.MyStackCount 
            //    + " of " + itemData.MyItemTitle 
            //    + " in " + itemData.MyBagIndex + " bag, in " 
            //    + itemData.MySlotIndex+" slot.");
        }

    }

    private void LoadEquipment(SaveScript data)
    {
        foreach (EquipmentData tempEqpData in data.MyEquipment)
        {
            charButton tlcb = Array.Find(equipment, x => x.name == tempEqpData.MyType);
            tlcb.EquipArmor(Array.Find(items, x => x.MyTitle == tempEqpData.MyTitle) as Equipment);
        }
    }

    private void LoadActionButtons(SaveScript data)
    {
        foreach(ActionBarData tempABD in data.MyActionBar) {
            if (tempABD.MyIsItem)
            {
                actionButtons[tempABD.MyIndex].setUsable(inventoryScript.MyInstance.UsableItem(tempABD.MyAction));
            }
            else
            {
                actionButtons[tempABD.MyIndex].setUsable(skillBook.MyInstance.getSkill(tempABD.MyAction));
            }
        }

    }
   
    private void Load(SavedCharacter sc)
    {
        try
        {
            saveNumber++;
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(Application.dataPath + "/publish/sav/" + sc.gameObject.name + ".dat",
                                        FileMode.Open);

            SaveScript data =(SaveScript)bf.Deserialize(file);
            
            file.Close();
            LoadEquipment(data);
            LoadPlayer(data);
            LoadChest(data);
            LoadBag(data);
            LoadInventory(data);
            LoadActionButtons(data);
            
        }
        catch (System.Exception)
        {
            Debug.Log("Load Catch");
            Delete(sc);
            SceneManager.LoadScene(0);
            PlayerPrefs.DeleteKey("Load");
        }
    }
    public void ShowDialog(GameObject button)
    {
        buttonEvent = button.name;
        switch (buttonEvent)
        {
            case "Load":
                questionDialogWindow.text = "Load game?";
                break;
            case "Save":
                questionDialogWindow.text = "Save game?";
                break;
            case "Delete":
                questionDialogWindow.text = "Delete game?";
                break;
        }
        curSavedGame = button.transform.parent.parent.GetComponent<SavedCharacter>();
        dialogWindowPopup.SetActive(true);
        
    }
    private void Delete(SavedCharacter sc)
    {
        File.Delete(Application.dataPath + "/publish/sav/" + sc.gameObject.name + ".dat");

        sc.HideInfo();
    }
    public void ExecuteAction()
    {
        switch (buttonEvent)
        {
            case "Load":
                LoadScene(curSavedGame);                
                break;
            case "Save":
                Save(curSavedGame);
                dialogWindowPopup.SetActive(false);
                break;
            case "Delete":
                Delete(curSavedGame);
                dialogWindowPopup.SetActive(false);
                break;
        }
    }
    private void LoadScene(SavedCharacter sc)
    {
        if (File.Exists(Application.dataPath + "/publish/sav/" + sc.gameObject.name + ".dat"))
        {
            
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(Application.dataPath + "/publish/sav/" + sc.gameObject.name + ".dat",
                                        FileMode.Open);
            SaveScript data = (SaveScript)bf.Deserialize(file);
            file.Close();
            PlayerPrefs.SetInt("Load",sc.MyIndex);

            SceneManager.LoadScene(data.MyScene);
        }
    }
}
